﻿using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;

/// <summary>
/// 对UI图形进行镜像处理
/// Image - Sample顶点顺序
/// ------
/// |1 /2|
/// |0/ 3|
/// ------
/// </summary>
[AddComponentMenu("UI/Effects/Mirror", 20)]
public class UIImageMirror : Image, IMeshModifier
{
    public enum MirrorDir
    {
        Horizontal, // 水平镜像
        Vertical,   // 垂直镜像
        Quater,     // 四方镜像（先水平，后垂直）
    }

    protected const int AxisX = 0;
    protected const int AxisY = 1;

    [SerializeField]
    private MirrorDir direction;

    public MirrorDir mirrorType
    {
        get { return direction; }
        set
        {
            if (direction != value)
            {
                direction = value;
                SetVerticesDirty();
            }
        }
    }

    public void ModifyMesh(Mesh mesh)
    {
        using (var vertexHelper = new VertexHelper(mesh))
        {
            ModifyMesh(vertexHelper);
            vertexHelper.FillMesh(mesh);
        }
    }

    public void ModifyMesh(VertexHelper verts)
    {
        if (!IsActive()) return;
        if (type == Image.Type.Simple)
        {
            SimpleMirror(verts);
        }
    }

    public override void SetNativeSize()
    {
        if (type == Image.Type.Simple)
        {
            SetShowNativeSize();
        }
        else { base.SetNativeSize(); }
    }

    protected override void OnPopulateMesh(VertexHelper toFill)
    {
        if (type != Image.Type.Simple)
        {
            base.OnPopulateMesh(toFill);
        }
        else
        {
            //if (!useSpriteMesh)
            //{
            //    GenerateSimpleSprite(toFill, preserveAspect);
            //}
            //else
            //{
            //    GenerateSprite(toFill, preserveAspect);
            //}
            base.OnPopulateMesh(toFill);
        }
    }

    private void SimpleMirror(VertexHelper toFill)
    {
        Rect rect = GetPixelAdjustedRect();
        ShrinkVert(toFill, rect);
        Vector2 doubleCenter = rect.center * 2;

        switch (direction)
        {
            case MirrorDir.Horizontal:
                SimpleMirrorHor(toFill, doubleCenter.x);
                break;
            case MirrorDir.Vertical:
                SimpleMirrorVer(toFill, doubleCenter.y);
                break;
            case MirrorDir.Quater:
                SimpleMirrorQuat(toFill, doubleCenter);
                break;
        }
    }

    private void SetShowNativeSize()
    {
        Sprite sprite = overrideSprite;
        float w = sprite.rect.width / pixelsPerUnit;
        float h = sprite.rect.height / pixelsPerUnit;
        rectTransform.anchorMax = rectTransform.anchorMin;

        switch (direction)
        {
            case MirrorDir.Horizontal:
                rectTransform.sizeDelta = new Vector2(w * 2, h);
                break;
            case MirrorDir.Vertical:
                rectTransform.sizeDelta = new Vector2(w, h * 2);
                break;
            case MirrorDir.Quater:
                rectTransform.sizeDelta = new Vector2(w * 2, h * 2);
                break;
        }
        SetAllDirty();
    }

    /// <summary>
    /// Simple模式的水平镜像
    /// 顶点布局：
    /// -----------
    /// |1 /2| \ 5|
    /// |0/ 3|  \4|
    /// -----------
    /// </summary>
    protected void SimpleMirrorHor(VertexHelper vh, float doubleX)
    {
        AddMirrorVert(vh, 0, AxisX, doubleX);  // 顶点4
        AddMirrorVert(vh, 1, AxisX, doubleX);  // 顶点5

        vh.AddTriangle(2, 4, 3);
        vh.AddTriangle(2, 5, 4);
    }

    /// <summary>
    /// Simple模式的垂直镜像
    /// 顶点布局：
    /// ------
    /// |4\ 5|
    /// |  \ |
    /// ------
    /// |1 /2|
    /// |0/ 3|
    /// ------
    /// </summary>
    protected void SimpleMirrorVer(VertexHelper vh, float doubleY)
    {
        AddMirrorVert(vh, 0, AxisY, doubleY);  // 顶点4
        AddMirrorVert(vh, 3, AxisY, doubleY);  // 顶点5

        vh.AddTriangle(2, 1, 4);
        vh.AddTriangle(2, 4, 5);
    }

    /// <summary>
    /// Simple模式的四方镜像
    /// 顶点布局：
    /// -----------
    /// |6 /7| \ 8|
    /// | /  |  \ |
    /// -----------
    /// |1 /2| \ 5|
    /// |0/ 3|  \4|
    /// -----------
    /// </summary>
    protected void SimpleMirrorQuat(VertexHelper vh, Vector2 doubleCenter)
    {
        // 水平
        AddMirrorVert(vh, 0, AxisX, doubleCenter.x);   // 顶点4
        AddMirrorVert(vh, 1, AxisX, doubleCenter.x);   // 顶点5
        vh.AddTriangle(2, 4, 3);
        vh.AddTriangle(2, 5, 4);

        // 垂直
        AddMirrorVert(vh, 0, AxisY, doubleCenter.y);   // 顶点6
        AddMirrorVert(vh, 3, AxisY, doubleCenter.y);   // 顶点7
        AddMirrorVert(vh, 4, AxisY, doubleCenter.y);   // 顶点8

        vh.AddTriangle(7, 1, 6);
        vh.AddTriangle(7, 2, 1);
        vh.AddTriangle(7, 5, 2);
        vh.AddTriangle(7, 8, 5);
    }

    /// <summary>
    /// 添加单个镜像顶点
    /// </summary>
    /// <param name="vh"></param>
    /// <param name="srcVertIdx">镜像源顶点的索引值</param>
    /// <param name="axis">轴向：0-X轴；1-Y轴</param>
    /// <param name="doubleCenter">Rect.center轴向分量的两倍值</param>
    protected static void AddMirrorVert(VertexHelper vh, int srcVertIdx, int axis, float doubleCenter)
    {
        UIVertex vert = UIVertex.simpleVert;
        vh.PopulateUIVertex(ref vert, srcVertIdx);
        Vector3 pos = vert.position;

        pos[axis] = doubleCenter - pos[axis];
        vert.position = pos; vh.AddVert(vert);
    }

    /// <summary>
    /// 收缩顶点坐标
    /// 根据镜像类型，将原始顶点坐标向“起始点(左/下)”收缩
    /// </summary>
    protected void ShrinkVert(VertexHelper vh, Rect rect)
    {
        int count = vh.currentVertCount;
        UIVertex vert = UIVertex.simpleVert;

        for (int i = 0; i < count; ++i)
        {
            vh.PopulateUIVertex(ref vert, i);
            Vector3 pos = vert.position;

            if (MirrorDir.Horizontal == direction || MirrorDir.Quater == direction)
            {
                pos.x = (rect.x + pos.x) * 0.5f;
            }

            if (MirrorDir.Vertical == direction || MirrorDir.Quater == direction)
            {
                pos.y = (rect.y + pos.y) * 0.5f;
            }
            vert.position = pos; vh.SetUIVertex(vert, i);
        }
    }

/*    private void PreserveSpriteAspectRatio(ref Rect rect, Vector2 spriteSize)
    {
        float num = spriteSize.x / spriteSize.y;
        float num2 = rect.width / rect.height;

        if (num > num2)
        {
            float height = rect.height;
            rect.height = rect.width * (1f / num);
            rect.y += (height - rect.height) * base.rectTransform.pivot.y;
        }
        else
        {
            float width = rect.width;
            rect.width = rect.height * num;
            rect.x += (width - rect.width) * base.rectTransform.pivot.x;
        }
    }

    private Vector4 GetDrawingDimensions(bool shouldPreserveAspect)
    {
        Vector4 vector = (overrideSprite == null) ? Vector4.zero : DataUtility.GetPadding(overrideSprite);
        Vector2 spriteSize = (overrideSprite == null) ? Vector2.zero : new Vector2(overrideSprite.rect.width, overrideSprite.rect.height);

        Rect rect = GetPixelAdjustedRect();
        int num = Mathf.RoundToInt(spriteSize.x);
        int num2 = Mathf.RoundToInt(spriteSize.y);

        Vector4 vector2 = new Vector4(vector.x / num, vector.y / num2, (num - vector.z) / num, (num2 - vector.w) / num2);
        if (shouldPreserveAspect && spriteSize.sqrMagnitude > 0f)
        {
            PreserveSpriteAspectRatio(ref rect, spriteSize);
        }

        return new Vector4(rect.x + rect.width * vector2.x, rect.y + rect.height * vector2.y,
            rect.x + rect.width * vector2.z, rect.y + rect.height * vector2.w);
    }

    private void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect)
    {
        Vector4 drawingDimensions = GetDrawingDimensions(lPreserveAspect);
        Vector4 vector = (overrideSprite != null) ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
        Color color = this.color;

        vh.Clear();
        vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.y), color, new Vector2(vector.x, vector.y));
        vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.w), color, new Vector2(vector.x, vector.w));
        vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.w), color, new Vector2(vector.z, vector.w));
        vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.y), color, new Vector2(vector.z, vector.y));
        vh.AddTriangle(0, 1, 2);
        vh.AddTriangle(2, 3, 0);
    }

    private void GenerateSprite(VertexHelper vh, bool lPreserveAspect)
    {
        Vector2 vector = new Vector2(overrideSprite.rect.width, overrideSprite.rect.height);
        Vector2 b = overrideSprite.pivot / vector;
        Vector2 pivot = rectTransform.pivot;

        Rect rect = GetPixelAdjustedRect();
        if (lPreserveAspect & (vector.sqrMagnitude > 0f))
        {
            PreserveSpriteAspectRatio(ref rect, vector);
        }

        Vector2 b2 = new Vector2(rect.width, rect.height);
        Vector3 size = overrideSprite.bounds.size;
        Vector2 vector2 = (pivot - b) * b2;
        Color color = this.color;

        vh.Clear();
        Vector2[] vertices = overrideSprite.vertices;
        Vector2[] uv = overrideSprite.uv;
        for (int i = 0; i < vertices.Length; i++)
        {
            vh.AddVert(new Vector3(vertices[i].x / size.x * b2.x - vector2.x, vertices[i].y 
                / size.y * b2.y - vector2.y), color, new Vector2(uv[i].x, uv[i].y));
        }

        ushort[] triangles = overrideSprite.triangles;
        for (int j = 0; j < triangles.Length; j += 3)
        {
            vh.AddTriangle(triangles[j], triangles[j + 1], triangles[j + 2]);
        }
    }*/
}